package com.summer.framework.gate.server.filter;

import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.ribbon.support.RibbonCommandContext;
import org.springframework.cloud.netflix.ribbon.support.RibbonRequestCustomizer;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter;
import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.List;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.*;

/**
 * @auther: 杨杰
 * @date: 2018/11/14 15:02
 * @description:
 */
@Slf4j
public class MyRibbonRoutingFilter extends RibbonRoutingFilter {

    public MyRibbonRoutingFilter(ProxyRequestHelper helper, RibbonCommandFactory<?> ribbonCommandFactory, List<RibbonRequestCustomizer> requestCustomizers) {
        super(helper, ribbonCommandFactory, requestCustomizers);
    }

    @Override
    public Object run() {
        log.info("========MyRibbonRoutingFilter run==========");
        RequestContext context = RequestContext.getCurrentContext();
        this.helper.addIgnoredHeaders(new String[0]);
        try {
            RibbonCommandContext commandContext = buildCommandContext(context);
            ClientHttpResponse response = forward(commandContext);
            this.setResponse(response);
            return response;
        } catch (ZuulException throwable) {
            log.info("ZuulException:");
            throw new ZuulRuntimeException(throwable);
        } catch (Exception throwable) {
            log.info("Exception:");
            throw new ZuulRuntimeException(throwable);
        }
    }

    public String buildZuulRequestURI(HttpServletRequest request) {
        log.info("========ProxyRequestHelper2=========buildZuulRequestURI");
        RequestContext context = RequestContext.getCurrentContext();
        String uri = request.getRequestURI();
        String contextURI = (String) context.get(REQUEST_URI_KEY);
        if (contextURI != null) {
            try {
                uri = UriUtils.encodePath(contextURI, "utf-8");
            } catch (Exception e) {
                log.debug(
                        "unable to encode uri path from context, falling back to uri from request",
                        e);
            }
        }
        return uri;
    }

    @Override
    protected RibbonCommandContext buildCommandContext(RequestContext context) {
        log.info("=========自定义的buildCommandContext=======");
        HttpServletRequest request = context.getRequest();

        MultiValueMap<String, String> headers = this.helper
                .buildZuulRequestHeaders(request);
        MultiValueMap<String, String> params = this.helper
                .buildZuulRequestQueryParams(request);
        String verb = getVerb(request);
        InputStream requestEntity = getRequestBody(request);
        if (request.getContentLength() < 0 && !verb.equalsIgnoreCase("GET")) {
            context.setChunkedRequestBody();
        }

        String serviceId = (String) context.get(SERVICE_ID_KEY);
        Boolean retryable = (Boolean) context.get(RETRYABLE_KEY);
        Object loadBalancerKey = context.get(LOAD_BALANCER_KEY);

        String uri = buildZuulRequestURI(request);
        ;

        // remove double slashes
        uri = uri.replace("//", "/");

        //long contentLength = super.useServlet31 ? request.getContentLengthLong(): request.getContentLength();

        return new RibbonCommandContext(serviceId, verb, uri, retryable, headers, params,
                requestEntity, this.requestCustomizers, request.getContentLengthLong(), loadBalancerKey);
    }

}
